﻿using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.Cookies;
using Sgr.Generator;
using System.Security.Claims;

namespace Sgr.Identity.Services
{
    public class CookieAuthenticationService : ICookieAuthenticationService
    {
        private readonly IHttpContextAccessor _httpContextAccessor;
        private readonly IStringIdGenerator _stringIdGenerator;

        public string AuthenticationScheme { get; set; } = CookieAuthenticationDefaults.AuthenticationScheme;

        public CookieAuthenticationService(IStringIdGenerator stringIdGenerator,
            IHttpContextAccessor httpContextAccessor)
        {
            _stringIdGenerator = stringIdGenerator;
            _httpContextAccessor = httpContextAccessor;
        }

        /// <summary>
        /// 登录
        /// </summary>
        /// <param name="account">用户信息</param>
        /// <param name="isPersistent">是否保留此标记表示的 Cookie 的值</param>
        /// <returns></returns>
        public virtual async Task SignInAsync(Account account, bool isPersistent)
        {
            Check.NotNull(account, nameof(account));

            var userPrincipal = CreateClaimsPrincipal(account);

            AuthenticationProperties authenticationProperties = createAuthenticationProperties(isPersistent);

            await _httpContextAccessor.HttpContext!.SignInAsync(AuthenticationScheme, userPrincipal, authenticationProperties);
        }

        private static AuthenticationProperties createAuthenticationProperties(bool isPersistent)
        {
            var authenticationProperties = new AuthenticationProperties
            {
                //是否在多次请求后保留身份验证会话
                IsPersistent = isPersistent,
                //票据颁发的时间
                IssuedUtc = DateTimeOffset.UtcNow
            };
            return authenticationProperties;
        }

        /// <summary>
        /// 登录
        /// </summary>
        /// <param name="account"></param>
        /// <param name="isPersistent"></param>
        /// <param name="additionalClaims"></param>
        /// <returns></returns>
        public virtual Task SignInWithClaimsAsync(Account account, bool isPersistent, IEnumerable<Claim> additionalClaims)
        {
            return SignInWithClaimsAsync(account, createAuthenticationProperties(isPersistent), additionalClaims);
        }

        /// <summary>
        /// 登录
        /// </summary>
        /// <param name="account"></param>
        /// <param name="authenticationProperties"></param>
        /// <param name="additionalClaims"></param>
        /// <returns></returns>
        public virtual async Task SignInWithClaimsAsync(Account account, AuthenticationProperties? authenticationProperties, IEnumerable<Claim> additionalClaims)
        {
            var userPrincipal = CreateClaimsPrincipal(account);

            foreach (var claim in additionalClaims)
            {
                userPrincipal.Identities.First().AddClaim(claim);
            }

            await _httpContextAccessor.HttpContext!.SignInAsync(AuthenticationScheme,
                userPrincipal,
                authenticationProperties ?? new AuthenticationProperties());

            _httpContextAccessor.HttpContext!.User = userPrincipal;
        }

        /// <summary>
        /// 更新登录状态
        /// </summary>
        /// <param name="account"></param>
        /// <returns></returns>
        public virtual async Task RefreshSignInAsync(Account account)
        {
            var auth = await _httpContextAccessor.HttpContext!.AuthenticateAsync(AuthenticationScheme);

            IList<Claim> claims = Array.Empty<Claim>();

            var authenticationMethod = auth?.Principal?.FindFirst(ClaimTypes.AuthenticationMethod);
            //var amr = auth?.Principal?.FindFirst("amr");

            if (authenticationMethod != null/* || amr != null*/)
            {
                claims = new List<Claim>();
                if (authenticationMethod != null)
                {
                    claims.Add(authenticationMethod);
                }

                //if (amr != null)
                //{
                //    claims.Add(amr);
                //}
            }

            await SignInWithClaimsAsync(account, auth?.Properties, claims);
        }

        /// <summary>
        /// 登出
        /// </summary>
        /// <returns></returns>
        public virtual async Task SignOutAsync()
        {
            await _httpContextAccessor.HttpContext!.SignOutAsync(AuthenticationScheme);
        }

        protected virtual ClaimsPrincipal CreateClaimsPrincipal(Account account)
        {
            var claims = new Claim[]
            {
                new Claim(System.IdentityModel.Tokens.Jwt.JwtRegisteredClaimNames.Jti,_stringIdGenerator.GenerateUniqueId()),//JWT的唯一标识符，可用于后续JWT黑名单处理逻辑
                new Claim(ClaimTypes.NameIdentifier, account.LoginName, ClaimValueTypes.String),
                new Claim(ClaimTypes.Name, account.DisplayName, ClaimValueTypes.String),
                new Claim(Constant.CLAIM_USER_ID, account.Id.ToString()),
                new Claim(Constant.CLAIM_USER_ORGID, account.OrgId.ToString(), ClaimValueTypes.String)
            };

            var userIdentity = new ClaimsIdentity(claims, AuthenticationScheme);

            return new ClaimsPrincipal(userIdentity);
        }
    }
}